//Casa@131007c
//
#include"global.h"
#include"hope.h"
#include"multi_array.h" 
#include"FDR.h"
using namespace std;
  
extern "C"{
	extern vector<vector<int>> ots;//original test set
	extern vector<vector<tuple<int, int>>> fts;//fliped test set.
	extern vector<unordered_set<uint32_t>> odfl;
	extern unordered_map<uint32_t, uint32_t> fault_map;
	extern void init_ots(const string &filename);
	extern void init_fts(const string &filename);

	//
	//--------------------------------------------------
	void output_test_set(const string &filename)
	{
		ofstream out(filename);
		ofstream fout(filename + ".hope");
		if (!out)
			ERR_MSG(filename + ":cannot open");
		for (auto &pattern : ots)
		{
			fout << ':';
			for (auto &bit : pattern)
			{
				out << bit;
				fout << bit;
				//	str+=(char)(bit+'0');
			}
			fout << endl;
			out << endl;
		}
		fout.close();
		out.close();
	}

	//////////////////////////////////////////////////////////
	int main(int argc, char **argv)
	{
		try{
			for (int k = 1; k < argc; k++){
				string filename("out/");
				filename += argv[k];

				init_ots(filename + ".hope_nox");
				init_fts(filename + ".diff");
				get_every_pattern_detected_fault(filename + ".sm", false);
				get_flip_pattern_detected_fault(filename + ".sm");

				for (auto &x : fts)
					sort(x.begin(), x.end(), [](const tuple<int, int>& a, const
					tuple<int, int>& b){return get<1>(a) < get<1>(b); });
				//test
				/*	for(auto &x:fts)
					{
					for(auto &y:x)
					cout<<get<0>(y)<<':'<<get<1>(y)<<' ';
					cout<<endl;
					}
					*/
				//------------------------------------------------------
				//
				odfl.clear();
				odfl.shrink_to_fit();
				extern vector<unordered_set<uint32_t>> ndfl;
				ndfl.clear();
				ndfl.shrink_to_fit();
				fault_map.clear();
				odfl.clear();
				odfl.shrink_to_fit();
				extern int nstep;
				nstep = 0;
				while (nstep < 1000)
				{
					cout << "step:" << nstep << endl;
					get_every_pattern_detected_fault(filename + ".sm", false);
					if (!get_every_pattern_detected_fault(filename + ".sm", true))
						break;
					//caculate the value
					//

					extern vector<unordered_set<uint32_t>> ndfl;
					extern vector<tuple<int, int>> nflip; //flip bit bye step[pattern,pos]
					vector<tuple<int, int>> weight;//pos,weight
					for (int i = 0; i < ndfl.size(); i++)
					{
						int pattern = get<0>(nflip[i]);
						int w = odfl[pattern].size() - ndfl[i].size();
						weight.emplace_back(i, w);
					}
					//
					//sort
					sort(weight.begin(), weight.end(), [](const tuple<int, int>& l,
						const tuple<int, int>& r){return get<1>(l) < get<1>(r); });
					//select
					vector<int> selected;
					for (int i = 0; i < weight.size(); ++i)
					{
						int index = get<0>(weight[i]);
						bool can = true;
						for (auto &x : odfl[get<0>(nflip[index])])
						{
							if (fault_map.find(x) == fault_map.end())
								cout << "error 101" << endl;
							if (ndfl[index].find(x) == ndfl[index].end() &&
								fault_map[x] < 2)
								can = false;
						}
						if (can)
						{
							selected.push_back(index);
							for (auto &x : ndfl[index])
							{
								auto p = fault_map.find(x);
								if (p == fault_map.end())
									continue;
								p->second++;
							}
							for (auto &x : odfl[get<0>(nflip[index])])
							{
								auto p = fault_map.find(x);
								if (p == fault_map.end())
									cout << "error" << endl;
								p->second--;
							}
							ots[get<0>(nflip[index])][get<1>(nflip[index])] ^= 1;
						}
					}
					cout << "select:" << selected.size() << endl;
					nstep++;

				}
				output_test_set(filename + ".flip");
			}
		}
		catch (exception &e)
		{
			cerr << "Main:" << e.what() << endl;
		}
		catch (generic_msg &e)
		{
			cerr << e.what() << endl;
		}
		cout << "Time used:\t" << clock() / 1000 << endl;
//		cin.get();
		return 0;
	}
}
